feat(redis): Set db.query.text span attributes#6639
Conversation
When using span streaming, set SPANDATA.DB_QUERY_TEXT on db.redis spans and SPANDATA.CACHE_KEY on cache spans. These were already set as the span description/name but were missing from the attributes dict in the streaming path. Refs PY-2549 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| @@ -116,6 +116,7 @@ def sentry_patched_execute_command( | |||
| attributes={ | |||
| "sentry.op": cache_properties["op"], | |||
| "sentry.origin": SPAN_ORIGIN, | |||
There was a problem hiding this comment.
Bug: The cache span is initialized with SPANDATA.CACHE_KEY set to the description string, not the key tuple, causing an incorrect attribute type in exception paths.
Severity: LOW
Suggested Fix
Modify the span creation to use the correct property from the start. Instead of setting SPANDATA.CACHE_KEY to cache_properties["description"], set it to cache_properties["key"]. This ensures the attribute has the correct type (a tuple of strings) from the moment of initialization, even in exception paths.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: sentry_sdk/integrations/redis/_sync_common.py#L118
Potential issue: The code in `_sync_common.py` and `_async_common.py` incorrectly
initializes the `SPANDATA.CACHE_KEY` attribute on the cache span with
`cache_properties["description"]`, which is a string. The correct value should be
`cache_properties["key"]`, a tuple of strings. While a subsequent call to
`_set_cache_data` overwrites this with the correct value in the normal execution flow,
this correction does not happen if an exception is raised during the Redis command
execution. In such an exception scenario, the span would be captured with the wrong
attribute type (a string instead of a list of strings), leading to inconsistent
telemetry data.
Also affects:
sentry_sdk/integrations/redis/_async_common.py:119~119
Did we get this right? 👍 / 👎 to inform future reviews.
Codecov Results 📊✅ 89837 passed | ⏭️ 6240 skipped | Total: 96077 | Pass Rate: 93.51% | Execution Time: 319m 40s 📊 Comparison with Base Branch
All tests are passing successfully. ✅ Patch coverage is 100.00%. Project has 2404 uncovered lines. Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 89.90% 89.89% -0.01%
==========================================
Files 192 192 —
Lines 23772 23775 +3
Branches 8212 8206 -6
==========================================
+ Hits 21370 21371 +1
- Misses 2402 2404 +2
- Partials 1341 1344 +3Generated by Codecov Action |
…che key attribute for now
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c758f7f. Configure here.
| with capture_internal_exceptions(): | ||
| additional_cache_span_attributes[SPANDATA.DB_QUERY_TEXT] = ( | ||
| _get_safe_command(name, args) | ||
| ) |
There was a problem hiding this comment.
Cache spans use db.query.text
Medium Severity
For span streaming, cache spans merge additional_cache_span_attributes using SPANDATA.DB_QUERY_TEXT and _get_safe_command, but this change was meant to populate cache.key on cache spans. That mislabels cache.get / cache.put spans with a database query attribute and does not add cache.key at span creation (only later via _set_cache_data).
Additional Locations (1)
Reviewed by Cursor Bugbot for commit c758f7f. Configure here.
There was a problem hiding this comment.
I think this comment still needs to be addressed @ericapisani
There was a problem hiding this comment.
This change was to address your earlier comment re: setting the full redis command without truncation as an attribute.
As part of this, I reversed the earlier change I had made introducing the cache.key attribute, so this bot comment is coming up because I forgot to update the title/description of the PR
There was a problem hiding this comment.
Cool another case of the bots being confused 😞. Approved now!
| assert ( | ||
| set1["attributes"][SPANDATA.DB_QUERY_TEXT] | ||
| == f"SET 'somekey1' '{long_string}'" | ||
| ) | ||
| assert set1["attributes"]["sentry.op"] == "db.redis" | ||
| assert set2["name"] == expected_short |
There was a problem hiding this comment.
DB_QUERY_TEXT span attribute bypasses user-configured max_data_size limit
In the span-streaming path, db.redis spans now set SPANDATA.DB_QUERY_TEXT to the raw output of _get_safe_command(name, args). Unlike the span description/name (computed by _get_db_span_description), this value is never truncated to integration.max_data_size. With send_default_pii=True, large Redis values (e.g. a 100,000-char SET payload) are stored verbatim in the attribute, producing very large span attributes that bypass the user's configured data-size cap and risk exceeding Sentry's ingest payload limits. The same pattern applies to the cache-key attribute in both _sync_common.py and _async_common.py.
Evidence
_get_db_span_descriptioninmodules/queries.pytruncates the span name tointegration.max_data_size(description[: max_data_size - 3] + '...'), and_get_cache_span_descriptioninmodules/caches.pydoes the same._get_safe_commandinredis/utils.pyonly limits arg count (_MAX_NUM_ARGS) and never truncates individual arg length or appliesmax_data_size._sync_common.py:141(and the equivalent in_async_common.py) assignsadditional_db_span_attributes[SPANDATA.DB_QUERY_TEXT] = _get_safe_command(name, args)and passes it straight into the streamed span attributes.- The new test
test_data_truncation_custom(test_redis.py:339-342) configuresmax_data_size=30yet assertsset1["attributes"][SPANDATA.DB_QUERY_TEXT] == f"SET 'somekey1' '{long_string}'"wherelong_string = 'a' * 100000, confirming the ~100k-char value is stored untruncated while the span name is truncated to 30.
Identified by Warden code-review · JGL-PYX


When using the span streaming path,
db.query.textwas not being set ondb.redisspansThis adds
SPANDATA.DB_QUERY_TEXTto spans in both the sync and async Redis common modules, and extends existing tests to assert these attributes are present.Fixes PY-2549
Fixes #6638